package models;

import java.util.*;

import javax.persistence.*;
import play.db.jpa.*;
import play.modules.search.Field;
import play.modules.search.Indexed;

/**
 * 
 * @author Mostafa Fahim
 * 
 * @version 1.0
 * 
 */
@Entity
public class Plan extends Model {

	@Lob
	public String description;
	public String title;
	public double status;
	public ArrayList<String> requirements;
	public Date startDate;
	public Date endDate;
	@OneToMany(mappedBy = "plan", cascade = CascadeType.PERSIST)
	public List<ActionItem> actionItems;
	public ArrayList<Long> toBeRemoved;
	@ManyToMany(mappedBy = "plans", cascade = CascadeType.PERSIST)
	public List<Idea> ideas;
	public ArrayList<Long> ideasToBeRemoved;
	@ManyToOne
	public User creator;
	@OneToMany(mappedBy = "plan", cascade = CascadeType.PERSIST)
	public List<PlanRating> usersRatings;
	@OneToMany(mappedBy = "sharedPlan", cascade = CascadeType.PERSIST)
	public List<SharedPlan> sharedPlans;
	public double planRating;
	public int numberOfView;
	@OneToMany
	public List<planComment> planComments;

	/**
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param title
	 *            title of the plan
	 * @param description
	 *            the description of the aim of the plan (what it will execute)
	 * @param status
	 *            the current status(progress of the plan in percentage)
	 * @param startDate
	 *            the date at which the plan will start execution
	 * @param endDate
	 *            the date at which the plan will end
	 * @param idea
	 *            the idea that this plan is execution
	 * @param creator
	 *            the organizer who initiated the plan
	 */

	public Plan(String title, String description, double status,
			Date startDate, Date endDate, User creator) {
		this.title = title;
		this.description = description;
		this.status = status;
		this.requirements = new ArrayList<String>();
		this.startDate = startDate;
		this.endDate = endDate;
		this.ideas = new ArrayList<Idea>();
		this.creator = creator;
		this.actionItems = new ArrayList<ActionItem>();
		usersRatings = new ArrayList<PlanRating>();
		this.numberOfView = 0;
		this.planComments = new LinkedList<planComment>();
	}

	public User getCreator() {
		return creator;
	}

	public void setCreator(User creator) {
		this.creator = creator;
	}

	/**
	 * adds new action item to the to-do-list of this plan
	 * 
	 * @param itemId
	 *            id of the item to be added to this plan
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @return Plan, the method returns the Plan instance after the
	 *         modifications
	 */

	public Plan addActionItem(long itemId) {
		ActionItem item = ActionItem.findById(itemId);
		item.setPlan(this.getId());
		this.actionItems.add(item);
		this.save();
		return this;
	}

	/**
	 * removes action item from this plan through adding the action item id into
	 * a list used to actually delete the action item objects
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param itemId
	 *            the id of the action item to be removed
	 * @return Plan , the Plan object after removing the action item
	 */
	public Plan removeActionItem(long itemId) {
		ActionItem item = ActionItem.findById(itemId);
		this.actionItems.remove(item);
		if (this.toBeRemoved == null) {
			this.toBeRemoved = new ArrayList<Long>();
		}
		this.toBeRemoved.add(item.id);
		this.save();
		return this;
	}

	/**
	 * restores action item to this plan through removing the action item id
	 * from a list used to actually delete the action item objects
	 * 
	 * @author Mostafa Fahim
	 * 
	 * @param itemId
	 *            the id of the action item to be restored
	 * @return Plan , the Plan object after restoring the action item
	 */
	public Plan restoreActionItem(long itemId) {
		this.toBeRemoved.remove(itemId);
		this.save();
		return this;
	}

	/**
	 * Used to remove an idea from this plan
	 * 
	 * @param ideaId
	 *            The ID of the idea to be removed
	 * @return (Plan this) This plan after removing an idea from it
	 * @author Sherif Ayad
	 * @story C5S65
	 */
	public Plan removeIdea(long ideaId) {
		Idea idea = Idea.findById(ideaId);
		if (this.ideasToBeRemoved == null) {
			this.ideasToBeRemoved = new ArrayList<Long>();
		}
		this.ideasToBeRemoved.add(idea.id);
		this.save();
		return this;
	}

	/**
	 * Used to restore an idea back to the list of ideas associated to this plan
	 * 
	 * @param ideaId
	 *            The ID of the idea to be restored
	 * @return (Plan this) This plan after restoring the idea to it
	 * @author Sherif Ayad
	 * @story C5S65
	 */
	public Plan restoreIdea(long ideaId) {
		this.ideasToBeRemoved.remove(ideaId);
		this.save();
		return this;
	}

	// Inserting add-requirement
	public void addRequirement(String req) {
		requirements.add(req);
	}

	/**
	 * method to remove requirement from a certain plan.
	 * 
	 * @param reqNo
	 *            requirement number
	 * @author Mostafa M. Ayman
	 * @return the method returns the Plan after removing the undesired
	 *         requirement
	 */
	public Plan removeRequirement(int reqNo) {
		this.requirements.remove(reqNo);
		this.save();
		return this;
	}

	/**
	 * method to edit a certain requirement from a certain plan.
	 * 
	 * @param reqNo
	 *            requirement number
	 * @param newRequirement
	 *            the new requirement instead of the old one, which was removed.
	 * @author Mostafa M. Ayman
	 * @return the method returns the Plan after editing the desired
	 *         requirement. Remove the requirement, add a new requirement
	 *         instead of the removed one. (with the same index)
	 */
	public Plan editRequirement(int reqNo, String newRequirement) {
		this.requirements.remove(reqNo);
		this.requirements.add(reqNo, newRequirement);
		this.save();
		return this;
	}

	// shows the requirements of a plan [Mustapha's]
	public void showReqs() {
		int l = requirements.size();
		String a[] = new String[l];
		requirements.toArray(a); // array-list to a normal array.
		for (int i = 0; i <= l; i++) {
			System.out.println(a[i]);
		}

	}

	// updating the plan status/ inserting a plan status [Mustapha's]
	public void updateStatus(double x) {
		double old_status = status;
		status = x;
	}

	/**
	 * Get the list of all ideas in the database
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @return List<Idea> The list of all ideas in the database
	 */
	public List<Idea> getAllIdeas() {
		return Idea.getListOfAllIdeas();
	}

	/**
	 * Add an idea to the list of ideas of the plan
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @param i
	 *            the idea to be added to the list of ideas
	 */
	public void addIdea(Idea i) {
		this.ideas.add(i);
	}

	/**
	 * Formats the start date like yy-mm-dd
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @return String startDate the formated string of the date
	 */

	public String formatStartDate() {
		if (startDate == null)
			return null;
		return startDate.toString().substring(0, 10);
	}

	/**
	 * Formats the end date like yy-mm-dd
	 * 
	 * @story C5S65
	 * @author Sherif Ayad
	 * @return String endDate the formated string of the date
	 */
	public String formatEndDate() {
		if (endDate == null)
			return null;
		return endDate.toString().substring(0, 10);
	}

	/**
	 * @author AkrAmAtion
	 * 
	 * @return a String that will be used to export search results displaying a
	 *         plan whose title matches a keyword. The String is formatted as
	 *         Comma-Separated-Values
	 * */
	public String toString() {
		return "PLAN," + title + "," + description + "," + creator;
	}

	/**
	 * it updates the overall rating of this plan.
	 * 
	 * @param newPlanRating
	 *            the new rating.
	 * @return Plan, the current instance.
	 * 
	 * @author Ahmed Mahmoud
	 */
	public Plan updateRating(double newPlanRating) {
		this.planRating = newPlanRating;
		this.save();
		return this;
	}

	/**
	 * Returns a substring of the description of the plan with length maximum 40
	 * chars
	 * 
	 * @author Islam Al-Aarag
	 * @story C4S66
	 * @return String a substring of the description of the plan
	 */
	public String getSummarizedContent() {
		if (description.length() < 40)
			return description;
		else
			return description.substring(0, 40) + "...";
	}

	/**
	 * @author Ahmed Mahmoud
	 * @return
	 * 
	 */
	public boolean cascadeDelete() {
		while (!actionItems.isEmpty()) {
			ActionItem actionItem = actionItems.get(0);
			actionItem.cascadeDelete();
		}
		for (Idea idea : ideas) {
			idea.plans.remove(this);
			idea.save();
		}
		creator.plans.remove(this);
		creator.save();
		while (!usersRatings.isEmpty()) {
			PlanRating planRating = usersRatings.get(0);
			planRating.cascadeDelete();
		}
		while (!sharedPlans.isEmpty()) {
			SharedPlan sharedPlan = sharedPlans.get(0);
			sharedPlan.cascadeDelete();
		}
		while (!planComments.isEmpty()) {
			planComment comment = planComments.get(0);
			comment.cascadeDelete();
		}
		this.delete();
		return true;
	}
}
